package com.spring.nio.verify;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;

/**
 * @author: YSFY
 * @date: 2021-06-16 08:56
 * @pacage_name: com.spring.nio.verify
 * @class_name: ClientThread
 * @description: 客户端非soLinger线程
 */
public class ClientNoSoLingerThread implements Runnable {
    @Override
    public void run() {
        OutputStream outputStream = null;
        InputStream inputStream = null;
        Socket socket = new Socket();
        try {
            // 1、连接服务端
            InetSocketAddress socketAddress = new InetSocketAddress(InetAddress.getByName("192.168.14.93"), 10090);
            socket.connect(socketAddress);

            // 2、测试点1: 向服务端发送完数据后客户端直接关闭连接
            //this.sendToServerThenClose(outputStream = socket.getOutputStream());

            // 3、测试点2: 接收服务端数据后，服务端关闭socket，客户端轮询read()会读取到-1
            //this.receiveFromServerWaitServerCloseThenLoopRead(socket.getInputStream());

            // 4、测试点3: 接收服务端数据后，服务端关闭socket，客户端尝试给服务端发送数据
            this.receiveFromServerWaitServerCloseThenSendToServer(socket.getInputStream(),socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            // 阻塞当前线程
            try {
                Thread.currentThread().join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 测试点1: 向服务端发送数据
     * @param outputStream
     * */
    private void sendToServerThenClose(OutputStream outputStream) throws IOException {
        /**
         * 客户端向输出流outputStream写出数据，写完后直接关闭客户端，调用socket.close()
         * 1、验证服务端read操作: 服务端socket 循环read操作将会读取到-1
         * 2、验证服务端write操作: 服务端socket 尝试写入会报出Broken pipe(writed failed)
         * */
        outputStream.write("测试tcp broken pipeline".getBytes(Charset.forName("utf-8")));
        outputStream.flush();
    }

    /**
     * 测试点2: 尝试不断接收服务端数据, 当服务端关闭了连接后,此时客户端再次read会生什么异常
     * @param inputStream
     * */
    private void receiveFromServerWaitServerCloseThenLoopRead(InputStream inputStream) throws IOException {
        int readSize = 0;
        byte[] bytes = new byte[1024];
        while ((readSize = inputStream.read(bytes)) > 0) {
            System.out.println("来自服务端数据, data = " + new String(bytes, 0, bytes.length));
            // 模拟客户端数据处理
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 测试点3: 接收服务端数据后，服务端关闭socket，客户端尝试给服务端发送数据
     * @param inputStream
     * @param outputStream
     * */
    private void receiveFromServerWaitServerCloseThenSendToServer(InputStream inputStream, OutputStream outputStream) throws IOException{
        int readSize = 0;
        byte[] bytes = new byte[1024];
        while ((readSize = inputStream.read(bytes)) > 0) {
            System.out.println("来自服务端数据, data = " + new String(bytes, 0, bytes.length));
            // 模拟客户端数据处理
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            break;
        }

        try {
            // 等待服务端关闭
            TimeUnit.MILLISECONDS.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        while (true) {
            outputStream.write("测试tcp broken pipeline".getBytes(Charset.forName("utf-8")));
            outputStream.flush();
        }
    }
}
